{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Short-Circuit Calculation according to IEC 60909\n",
    "\n",
    "pandapower supports short-circuit calculations with the method of equivalent voltage source at the fault location according to IEC 60909. The pandapower short-circuit calculation supports the following elements:\n",
    "\n",
    "- sgen (as motor or as full converter generator or as asynchronous machine or as doubly-fed asynchronous machine)\n",
    "- gen (as synchronous generator)\n",
    "- ext_grid\n",
    "- line\n",
    "- trafo\n",
    "- trafo3w\n",
    "- impedance\n",
    "\n",
    "with the correction factors as defined in IEC 60909. Loads and shunts are neglected as per standard. The pandapower switch model is fully integrated into the short-circuit calculation. \n",
    "\n",
    "The following short-circuit currents can be calculated:\n",
    "- ikss (Initial symmetrical short-circuit current)\n",
    "- ip (short-circuit current peak)\n",
    "- ith (equivalent thermal short-circuit current)\n",
    "\n",
    "either as\n",
    "\n",
    " - symmetrical three-phase or\n",
    " - asymmetrical two-phase\n",
    " \n",
    "short circuit current. Calculations are available for meshed as well as for radial networks. ip and ith are only implemented for short circuits far from synchronous generators.\n",
    "\n",
    "In addition, short-circuit calculation with the superposition method is implemented. With this method, the pre-fault voltage is considered. The following differences to the worst-case calculation apply:\n",
    "- transformer correction factor is not applied\n",
    "- load, sgen are additionally modelled as shunt admittances (calculated based on their pre-fault currents)\n",
    "- the grid must contain the results of a successful power flow calculation\n",
    "\n",
    "The results for all elements and different short-circuit currents are tested against commercial software to ensure that correction factors are correctly applied. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Example Network\n",
    "\n",
    "Here is a little example on how to use the short-circuit calculation. First, we create a simple open ring network with 4 buses, that are connected by one transformer and two lines with one open sectioning point. The network is fed by an external grid connection at bus 1:\n",
    "\n",
    "<div style=\"background-color: white; display: inline-block; padding: 5px;\">\n",
    "    <img src=\"./example_network_sc.png\">\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pandapower.shortcircuit import calc_sc\n",
    "from pandapower.create import (\n",
    "    create_empty_network,\n",
    "    create_bus,\n",
    "    create_ext_grid,\n",
    "    create_lines,\n",
    "    create_switch,\n",
    "    create_transformer,\n",
    "    create_sgen,\n",
    "    create_gen\n",
    ")\n",
    "from pandapower.run import runpp\n",
    "import warnings\n",
    "warnings.simplefilter(action='ignore', category=FutureWarning)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def ring_network():\n",
    "    net = create_empty_network()\n",
    "    b1 = create_bus(net, 220)\n",
    "    b2 = create_bus(net, 110)\n",
    "    b3 = create_bus(net, 110)\n",
    "    b4 = create_bus(net, 110)\n",
    "    create_ext_grid(net, b1, s_sc_max_mva=100., s_sc_min_mva=80., rx_min=0.20, rx_max=0.35)\n",
    "    create_transformer(net, b1, b2, \"100 MVA 220/110 kV\")\n",
    "    _, l2, _ = create_lines(net, [b2, b3, b4], [b3, b4, b2], std_type=\"N2XS(FL)2Y 1x120 RM/35 64/110 kV\" , length_km=[15, 12, 10])\n",
    "    create_switch(net, b4, l2, closed=False, et=\"l\")\n",
    "    return net"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Symmetric Short-Circuit Calculation\n",
    "\n",
    "### Maximum Short Circuit Currents\n",
    "Now, we load the network and calculate the maximum short-circuit currents with the calc_sc function:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "net = ring_network()\n",
    "calc_sc(net, case=\"max\", ip=True, ith=True, branch_results=True)\n",
    "net.res_bus_sc"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "where ikss is the initial short-circuit current, ip is the peak short-circuit current and ith is the thermal equivalent current.\n",
    "\n",
    "For branches, the results are defined as the maximum current flows through that occurs for a fault at any bus in the network. The results are available seperately for lines:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "net.res_line_sc"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "and transformers:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "net.res_trafo_sc"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Minimum Short Circuit Currents"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Minimum short-circuits can be calculated in the same way. However, we need to specify the end temperature of the lines after a fault as per standard first:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "net = ring_network()\n",
    "net.line[\"endtemp_degree\"] = 80\n",
    "calc_sc(net, case=\"min\", ith=True, ip=True, branch_results=True)\n",
    "net.res_bus_sc"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The branch results are now the minimum current flows through each branch:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "net.res_line_sc"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "net.res_trafo_sc"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Asynchronous Motors\n",
    "\n",
    "Asynchronous motors can be specified by creating a static generator of type \"motor\". For the short circuit impedance, an R/X ratio \"rx\" as well as the ratio between nominal current and short circuit current \"k\" has to be specified:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "net = ring_network()\n",
    "create_sgen(net, 2, p_mw=0, sn_mva=0.5, k=1.2, rx=7., type=\"motor\")\n",
    "net"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If we run the short-circuit calculation again, we can see that the currents increased due to the contribution of the inverteres to the short-circuit currents."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "calc_sc(net, case=\"max\", ith=True, ip=True)\n",
    "net.res_bus_sc"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Synchronous Generators\n",
    "\n",
    "Synchronous generators can also be considered in the short-circuit calculation with the gen element. According to the standard, the rated power factor (cos$\\varphi$) \"cos_phi\", rated voltage \"vn_kv\", rated apparent power \"sn_kva\" and subtransient resistance \"rdss\" and reactance \"xdss\" are necessary to calculate the short circuit impedance:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "net = ring_network()\n",
    "create_gen(net, 2, p_mw=0, vm_pu=1.0, cos_phi=0.8, vn_kv=22, sn_mva=5, xdss_pu=0.2, rdss_ohm=0.005)\n",
    "net"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "and run the short-circuit calculation again:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "calc_sc(net, case=\"max\", ith=True, ip=True)\n",
    "net.res_bus_sc"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Once again, the short-circuit current increases due to the contribution of the generator. As can be seen in the warning, the values for peak and thermal equivalent short-circuit current will only be accurate for faults far from generators."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Meshed Networks\n",
    "\n",
    "The correction factors for aperiodic and thermal currents differ between meshed and radial networks. pandapower includes a meshing detection that automatically detects the meshing for each short-circuit location. Alternatively, the topology can be set to \"radial\" or \"meshed\" to circumvent the check and save calculation time.\n",
    "\n",
    "We load the radial network and close the open sectioning point to get a closed ring network:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "net = ring_network()\n",
    "net.switch.closed = True\n",
    "calc_sc(net, topology=\"auto\", ip=True, ith=True)\n",
    "net.res_bus_sc"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "the network is automatically detected to be meshed and application factors are applied. This can be validated by setting the topology to radial and comparing the results:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "calc_sc(net, topology=\"radial\", ip=True, ith=True)\n",
    "net.res_bus_sc"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If we look at the line results, we can see that the line currents are significantly smaller than the bus currents:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "calc_sc(net, topology=\"auto\", ip=True, ith=True, branch_results=True)\n",
    "net.res_line_sc"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "this is because the short-circuit current is split up on both paths of the ring, which is correctly considered by pandapower."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Fault Impedance\n",
    "\n",
    "It is also possible to specify a fault impedance in the short-circuit calculation:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "net = ring_network()\n",
    "calc_sc(net, topology=\"radial\", ip=True, ith=True, r_fault_ohm=1., x_fault_ohm=2.)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "which of course decreases the short-circuit currents:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "net.res_bus_sc"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Superposition method\n",
    "\n",
    "We need to first execute the power flow calculation so that the grid has valid power flow results. We rely on the user to execute this step explicitly so that the user is fully aware that a power flow calculation is executed and also has control over all the relevant options for the power flow calculation.\n",
    "\n",
    "Next, we pass the parameter use\\_pre\\_fault\\_voltage = True to use the superposition method."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "runpp(net)\n",
    "calc_sc(net, topology=\"radial\", ip=True, ith=True, r_fault_ohm=1., x_fault_ohm=2.,\n",
    "           branch_results=True, return_all_currents=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "net.res_bus_sc"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "net.res_line_sc"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The results above show the line results for the short-circuit calculation. The result table has a MultiIndex, which means that the results are shown for every line (\"line\" index column) and for every situation defined by a different fault location bus separately (index column \"bus\"). Note that not only the current magnitude values are available, but also the current angles, along with active and reactive power flows, and voltage magnitude and angle."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Asymetrical Two-Phase Short-Circuit Calculation\n",
    "\n",
    "All calculations above can be carried out for a two-phase short-circuit current in the same way by specifying \"2ph\" in the fault parameter:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "net = ring_network()\n",
    "calc_sc(net, fault=\"2ph\", ip=True, ith=True)\n",
    "net.res_bus_sc"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Two phase short-circuits are often used for minimum short-circuit calculations:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "net = ring_network()\n",
    "net.line[\"endtemp_degree\"] = 150\n",
    "calc_sc(net, fault=\"2ph\", case=\"min\", ip=True, ith=True)\n",
    "net.res_bus_sc"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Single Phase Short-Circuit Calculation\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "pandapower can also calculate single phase short-circuits. The ground fault however depends on the zero-sequence parameters of the network, which have to be added in order to calculate a single line to ground fault:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "net = ring_network()\n",
    "\n",
    "#r/x ratio in zero sequence parameters\n",
    "net.ext_grid[\"r0x0_max\"] = 0.4\n",
    "net.ext_grid[\"x0x_max\"] = 1.0\n",
    "\n",
    "#zero sequence line parameters\n",
    "net.line[\"r0_ohm_per_km\"] = 0.244\n",
    "net.line[\"x0_ohm_per_km\"] = 0.336\n",
    "net.line[\"c0_nf_per_km\"] = 2000\n",
    "\n",
    "#transformer vector group, zero sequence short circuit voltage\n",
    "#and zero sequence magnetizing impedance\n",
    "net.trafo[\"vector_group\"] = \"Dyn\"\n",
    "net.trafo[\"vk0_percent\"] = 5.\n",
    "net.trafo[\"vkr0_percent\"] = 0.4\n",
    "net.trafo[\"mag0_percent\"] = 10\n",
    "net.trafo[\"mag0_rx\"] = 0.4\n",
    "net.trafo[\"si0_hv_partial\"] = 0.9"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "calc_sc(net, fault=\"1ph\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "net.res_bus_sc"
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
